package org.wxd.springcloud.mdc.web;


import com.google.common.collect.Lists;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.wxd.springcloud.mdc.config.mdc.MdcThreadPoolTaskExecutor;

import java.util.List;
import java.util.concurrent.*;

@Slf4j
@RestController
public class MDCController {

    /**
     * 默认情况下由于父子线程没有通信 导致了mdc的traceId没有
     * @param id
     * @return
     * @throws Exception
     */
    @HystrixCommand(fallbackMethod = "hystrixFallback")
    @GetMapping("/mdcHystrix/{id}")
    public String hystrix(@PathVariable String id) throws Exception {
        log.info("mdc id={}",id);
        if (id.equalsIgnoreCase("2")) {
            int i = 1 / 0;
        }
        return id;
    }


    public String hystrixFallback(String id,Throwable e){
        log.error("fallback id={}",id,e);
        return "i";
    }



    @GetMapping("/mdc/{id}")
    public String mdc(@PathVariable String id){
        log.info("mdc id={}",id);
        return id;
    }

    private ExecutorService executorService = Executors.newFixedThreadPool(1);

//    private static MdcThreadPoolTaskExecutor taskExecutor;

    private static ThreadPoolTaskExecutor taskExecutor;


    static {
        taskExecutor = new ThreadPoolTaskExecutor();
        // 核心线程数
        taskExecutor.setCorePoolSize(5);
        // 最大线程数
        taskExecutor.setMaxPoolSize(50);
        // 队列最大长度
        taskExecutor.setQueueCapacity(1000);
        // 线程池维护线程所允许的空闲时间(单位秒)
        taskExecutor.setKeepAliveSeconds(120);
        // 线程池对拒绝任务(无线程可用)的处理策略 ThreadPoolExecutor.CallerRunsPolicy策略 ,调用者的线程会执行该任务,如果执行器已关闭,则丢弃.
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());

        taskExecutor.initialize();
    }

    /**
     * 同样父子线程没有通信 导致mdc的traceId不见
     * @param id
     * @return
     */
    @GetMapping("/async/execute/{id}")
    public String execute(@PathVariable String id){
        log.info("execute id={}",id);

        for (int i = 0; i < 100; i++) {
            final int val = i;
            taskExecutor.execute(() -> {
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("executors execute val={}",val);

            });
        }

        return id;
    }


    /**
     * 同样父子线程没有通信 导致mdc的traceId不见
     * @param id
     * @return
     */
    @GetMapping("/async/submit/{id}")
    public String submit(@PathVariable String id){
        log.info("submit id={}",id);

        for (int i = 0; i < 100; i++) {
            final int val = i;
            taskExecutor.submit(() -> {
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("executors submit val={}",val);
            });
        }

        return id;
    }


    /**
     * 同样父子线程没有通信 导致mdc的traceId不见
     * @param id
     * @return
     */
    @GetMapping("/async/call/{id}")
    public String call(@PathVariable String id){
        log.info("call id={}",id);
        List<Future<Integer>> futureList = Lists.newArrayList();
        for (int i = 0; i < 100; i++) {
            final int val = i;
            futureList.add(taskExecutor.submit(() -> {
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                log.info("executors call val={}",val);
                return val;
            }));
        }

        futureList.forEach(c -> {
            try {
                log.info("call get val ={}",c.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        });

        log.info("call done...");

        return id;
    }
}
